#include "CMdlTreeNode.h"
#include "CMdlTreeView.h"
#include <stack>

//-------------------------------------

CMdlTreeNode::CMdlTreeNode()
    : Entity(0),
      Owner(0),
      Index (-1),
      ChildNodesCount(0),
      NextSibling(0),
      PrevSibling(0),
      tree(0),
      baseTreeWidgetItem(0)
{
}

//-------------------------------------

CMdlTreeNode::CMdlTreeNode( CMdlTreeView * _tree, CEntity * e, CMdlTreeNode * _owner )
    : Entity( e ),
      Owner( _owner ),
      Index (-1),
      ChildNodesCount(0),
      NextSibling(0),
      PrevSibling(0),
      Text( _tree->GetEntityText( e ) ),
      tree( _tree ),
      baseTreeWidgetItem(0)
{
}

//-------------------------------------

CMdlTreeNode & CMdlTreeNode::operator = ( const CMdlTreeNode & src )
{
    Entity =src.Entity;
    Owner = src.Owner;
    nodes = src.nodes;
    Index = src.Index;
    ChildNodesCount = src.ChildNodesCount;
    Text = src.Text;
    tree = src.tree;
    return *this;
}

//-------------------------------------

CMdlTreeNode * CMdlTreeNode::PushToMap( std::vector<CMdlTreeNode*> & map, CEntity * e )
{
    CMdlTreeNode * res(0);
    Index = map.size();
    map.push_back( this );
    for( unsigned int i = 0; i!=nodes.size(); ++i )
        if( CMdlTreeNode * tmp = nodes[i].PushToMap( map, e ) )
            res = tmp;
    if( !res )
        if( Entity == e )
            res = this;
    return res;
}

//-------------------------------------

bool CMdlTreeNode::operator < ( const CMdlTreeNode & x ) const
{
    return ( Text.compare(x.Text) < 0 );
}

//-------------------------------------

void CMdlTreeNode::Update( CMdlTreeTraits * treeTraits )
{
    nodes.clear();

    int right( tree->GetNodeRect( this, 0, 0 ).right());
    if( right > treeTraits->maxRight )
        treeTraits->maxRight = right;

    if( Expanded )
    {
        typedef CNested::iterator Iter;
        Iter first( Entity->Nested().begin() );
        Iter last( Entity->Nested().end() );
        for( ; first != last; ++first )
            nodes.push_back( CMdlTreeNode( tree, *first, this ) );
        for( unsigned int i = 0; i != nodes.size(); )
        {
            CMdlTreeNode & node( nodes[i] );
            node.Update( treeTraits );
            ChildNodesCount += (node.ChildNodesCount + 1);
            if( i )
                node.PrevSibling = &(nodes[i-1]);
            else
                node.PrevSibling = 0;
            ++i;
            if( i!=nodes.size() )
                node.NextSibling = &(nodes[i]);
            else
                node.NextSibling = 0;
        }
    }
}

//-------------------------------------

bool CMdlTreeNode::GetCollapsed() const
{
    return tree->EntityNodeCollapsed( Entity );
}

//-------------------------------------

bool CMdlTreeNode::GetExpanded() const
{
    return tree->EntityNodeExpanded( Entity );
}

//-------------------------------------

bool CMdlTreeNode::GetHasChildren() const
{
    return !( Entity->Nested().empty() );
}

//-------------------------------------

void CMdlTreeNode::Expand()
{
    if( HasChildren )
        tree->ExpandEntityNode( Entity );
}

//-------------------------------------

void CMdlTreeNode::Collapse()
{
    if( HasChildren )
        tree->CollapseEntityNode( Entity );
}

//-------------------------------------

void CMdlTreeNode::ChangeState()
{
    if( Expanded )
        Collapse();
    else
        Expand();
}

//-------------------------------------

int CMdlTreeNode::GetLevel() const
{
    CMdlTreeNode * node( Owner );
    int i(0);
    for( ; node; ++i )
        node = node->Owner;
    return i;
}

//-------------------------------------

CMdlTreeNode * CMdlTreeNode::FindChildNodeOfEntity( CEntity * e )
{
    for( unsigned int i = 0; i != nodes.size(); ++i )
        if( nodes[i].Entity == e )
            return &(nodes[i]);
    return 0;
}

//-------------------------------------

CMdlTreeNode * CMdlTreeNode::FindNodeOfEntity( CEntity * e )
{
    if( e == Entity )
        return this;

    CMdlTreeNode * root = this;

    std::stack< CEntity* > stack;
    while( e && ( e != root->Entity ) )
    {
        stack.push( e );
        e = e->Owner();
    }

    if( stack.empty() )
        return 0;

    while ( ( !stack.empty() ) && root )
    {
        root = root->FindChildNodeOfEntity( stack.top() );
        stack.pop();
    }
    return root;
}

//-------------------------------------

